/**
 * 
 */
package org.going.utils;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.going.invoker.AfterInspector;
import org.going.invoker.BeforeInspector;

/**
 * @author ferendo.huang@gmail.com
 * 
 */
public final class ClassUtils implements GoingConst
{
	private static Set<Class<?>> primitiveClassSet;
	private static Set<Class<?>> primitiveArrayClassSet;
	private static Map<Class<? extends BeforeInspector>, BeforeInspector> beforeInspectorMap = new HashMap<Class<? extends BeforeInspector>, BeforeInspector>();
	private static Map<Class<? extends AfterInspector>, AfterInspector> afterInspectorMap = new HashMap<Class<? extends AfterInspector>, AfterInspector>();

	static
	{
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		classSet.add(short.class);
		classSet.add(Short.class);
		classSet.add(byte.class);
		classSet.add(Byte.class);
		classSet.add(int.class);
		classSet.add(Integer.class);
		classSet.add(long.class);
		classSet.add(Long.class);
		classSet.add(float.class);
		classSet.add(Float.class);
		classSet.add(double.class);
		classSet.add(Double.class);
		classSet.add(boolean.class);
		classSet.add(Boolean.class);
		classSet.add(char.class);
		classSet.add(Character.class);
		classSet.add(String.class);
		primitiveClassSet = Collections.unmodifiableSet(classSet);
		Set<Class<?>> arrClassSet = new HashSet<Class<?>>();
		arrClassSet.add(short[].class);
		arrClassSet.add(Short[].class);
		arrClassSet.add(byte[].class);
		arrClassSet.add(Byte[].class);
		arrClassSet.add(int[].class);
		arrClassSet.add(Integer[].class);
		arrClassSet.add(long[].class);
		arrClassSet.add(Long[].class);
		arrClassSet.add(float[].class);
		arrClassSet.add(Float[].class);
		arrClassSet.add(double[].class);
		arrClassSet.add(Double[].class);
		arrClassSet.add(boolean[].class);
		arrClassSet.add(Boolean[].class);
		arrClassSet.add(char[].class);
		arrClassSet.add(Character[].class);
		arrClassSet.add(String[].class);
		primitiveArrayClassSet = Collections.unmodifiableSet(arrClassSet);
	}

	/**
	 * @param clazz
	 * @return true if the class is a primitive class
	 */
	public static boolean isPrimitiveClass(Class<?> clazz)
	{
		return primitiveClassSet.contains(clazz);
	}

	/**
	 * @param clazz
	 * @return true if the array class is a primitive array class
	 */
	public static boolean isPrimitiveArrayClass(Class<?> clazz)
	{
		return primitiveArrayClassSet.contains(clazz);
	}

	/**
	 * @param clazz
	 * @param val
	 * @return object cast to the class
	 */
	public static Object toPrimitiveObject(Class<?> clazz, String val)
	{
		boolean empty = StringUtils.empty(val);
		if (Integer.class.equals(clazz) || int.class.equals(clazz))
		{
			return empty ? 0 : Integer.valueOf(val);
		}
		if (Long.class.equals(clazz) || long.class.equals(clazz))
		{
			return empty ? 0 : Long.valueOf(val);
		}
		if (Double.class.equals(clazz) || double.class.equals(clazz))
		{
			return empty ? 0 : Double.valueOf(val);
		}
		if (Byte.class.equals(clazz) || byte.class.equals(clazz))
		{
			return empty ? 0 : Byte.valueOf(val);
		}
		if (Short.class.equals(clazz) || short.class.equals(clazz))
		{
			return empty ? 0 : Short.valueOf(val);
		}
		if (Character.class.equals(clazz) || char.class.equals(clazz))
		{
			return empty ? Character.MIN_VALUE : val.toCharArray()[0];
		}
		return val;
	}

	public static boolean isArray(Class<?> clazz)
	{
		if (clazz.getName().startsWith(BRACKET_LEFT))
			return true;
		return false;
	}

	public static BeforeInspector getBeforeInspector(Class<? extends BeforeInspector> clazz)
			throws InstantiationException, IllegalAccessException
	{
		BeforeInspector inspector = beforeInspectorMap.get(clazz);
		if (inspector == null)
		{
			synchronized (beforeInspectorMap)
			{
				inspector = beforeInspectorMap.get(clazz);
				if (inspector == null)
				{
					inspector = (BeforeInspector) clazz.newInstance();
					beforeInspectorMap.put(clazz, inspector);
				}
			}
		}
		return inspector;
	}

	public static AfterInspector getAfterInspector(Class<? extends AfterInspector> clazz)
			throws InstantiationException, IllegalAccessException
	{
		AfterInspector inspector = afterInspectorMap.get(clazz);
		if (inspector == null)
		{
			synchronized (afterInspectorMap)
			{
				inspector = afterInspectorMap.get(clazz);
				if (inspector == null)
				{
					inspector = (AfterInspector) clazz.newInstance();
					afterInspectorMap.put(clazz, inspector);
				}
			}
		}
		return inspector;
	}
}
